/**
 * ForceFeedback Joystick Driver for Java
 * http://sourceforge.net/projects/ffjoystick4java/
 *
 * -----------------------------------------------------------------------------
 *
 * Copyright (c) 2010, Martin Wischenbart All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met: *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer. * Redistributions in binary
 * form must reproduce the above copyright notice, this list of conditions and
 * the following disclaimer in the documentation and/or other materials provided
 * with the distribution. * Neither the name of the ForceFeedback Joystick
 * Driver for Java nor the names of its contributors may be used to endorse or
 * promote products derived from this software without specific prior written
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * -----------------------------------------------------------------------------
 *
 * If you have any suggestions, or if you want to report a bug, please see
 * http://sourceforge.net/projects/ffjoystick4java/ or contact me via email.
 *
 * Martin Wischenbart elboato@users.sourceforge.net
 *
 */
package central;

import at.wisch.joystick.FFJoystick;
import at.wisch.joystick.Joystick;
import at.wisch.joystick.JoystickManager;
import at.wisch.joystick.event.*;
import at.wisch.joystick.exception.FFJoystickException;
import at.wisch.joystick.ffeffect.Effect;
import at.wisch.joystick.ffeffect.ExtendedEffect;
import at.wisch.joystick.ffeffect.direction.Direction;
import at.wisch.joystick.ffeffect.direction.SphericalDirection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.*;

/**
 * The JoystickControl GUI. It creates a graphical user interface to view the
 * inputs of different joysticks and play various force feedback effects.
 *
 * @see JoystickInputDemo
 * @see JoystickInputDemo
 *
 * @author Martin Wischenbart
 */
public class JoystickControl extends Thread implements ControllerEventListener, FeatureNotSupportedEventListener {

    private static final long serialVersionUID = 7989078461104748962L;
    private static JoystickControl jsTest;
    public static boolean running;
    private static ArrayList<Joystick> joysticks;
    private static Joystick joystick;
    static FFJoystick ffjoystick;
    private static ExtendedEffect simpleEffect;
    public static double[] channel = new double[12];
    public static int joyStickFound = 0;
    public static String name = "empty";

    //CONSTRUCTOR
    public int initJoystickControl() {
        try {
            JoystickManager.init();
            joysticks = JoystickManager.getAllJoysticks();
            joystick = JoystickManager.getJoystick();
            running = true;
            name = joystick.getName();

        } catch (FFJoystickException e) {
            e.printErrorMessage();
        }
        if (joysticks.isEmpty()) {
            name = "empty";
            return 0;
        }
        return joysticks.size();
    }

    /**
     * Sets the Joystick used for displaying input and playing effects.
     *
     * @param js the joystick object
     */
    public static void setJoystick(Joystick js) {
        if (ffjoystick != null) {
            ffjoystick.destroyAll();
        }
        joystick = js;
        System.out.println("Selected " + js.getName());
        System.out.println(" -> " + js.getDescription());
        if (joystick.isFFJoystick()) {

            ffjoystick = (FFJoystick) joystick;
            System.out.print(" -> ForceFeedback supported: ");
            System.out.println(ffjoystick.getFFDescription());

            if (ffjoystick.getName().equals("Logitech Force 3D Pro USB")) {
                // we set different dead zones for different axes
                ffjoystick.setDeadZone(0, 0.01f);
                ffjoystick.setDeadZone(1, 0.01f);
                ffjoystick.setDeadZone(2, 0.2f);
                ffjoystick.setDeadZone(3, 0.2f);
            }
            // we could add special adjustments for other joysticks here....
        }
    }

    @Override
    public void run() {

        while (true) {
            //Init Joysticks
            joyStickFound = initJoystickControl();
            if (joyStickFound == 0) {
                try {
                    JoystickManager.close();
                    Thread.sleep(2000); //X
                } catch (InterruptedException e) {
                };
            } else {
                //Joysticks found
                dataLoop();
            }

        }

    }

    //Update Data as long as Joystick is present
    private void dataLoop() {
        do {
            try {
                joyStickFound = JoystickManager.getAllJoysticks().size();
            } catch (FFJoystickException e) {
                e.printErrorMessage();
            }
            if (joyStickFound == 0) {
                return;
            }

            joystick.poll();

            float f;
            int channel_nr;
            for (channel_nr = 0; channel_nr < joystick.getAxisCount(); channel_nr++) {
                f = joystick.getAxisValue(channel_nr);
                channel[channel_nr] = f;

            }
            Boolean button;
            for (int b = 0; b < joystick.getButtonCount(); b++) {
                button = joystick.isButtonPressed(b);
                if (button == true) {
                    channel[channel_nr + b] = 1.00;
                } else {
                    channel[channel_nr + b] = 0.0;
                }
            }

            //update the state every X ms -> sleep for some time
            try {
                Thread.sleep(50); //X
            } catch (InterruptedException e) {
                e.printStackTrace();
                joyStickFound = 0;
            }
        } while (joyStickFound > 0);

    }


    /*
     * (non-Javadoc) @see
     * at.wisch.joystick.event.ControllerEventListener#controllerEventOccured(at.wisch.joystick.event.AdvancedControllerEvent)
     */
    @Override
    public void controllerEventOccured(AdvancedControllerEvent event) {
        System.out.println(event);

    }

    /*
     * (non-Javadoc) @see
     * at.wisch.joystick.event.FeatureNotSupportedEventListener#featureNotSupportedEventOccured(at.wisch.joystick.event.FeatureNotSupportedEvent)
     */
    @Override
    public void featureNotSupportedEventOccured(FeatureNotSupportedEvent event) {
        System.out.println(event);
    }
}

class JoystickSelectionActionListener implements ActionListener {

    private Joystick js;

    JoystickSelectionActionListener(Joystick js) {
        this.js = js;
    }

    public void actionPerformed(ActionEvent e) {
        JoystickControl.setJoystick(js);
    }
}

class StrengthSelectionActionListener implements ActionListener {

    private Effect effect;
    private int strength;

    StrengthSelectionActionListener(Effect effect, int strength) {
        this.effect = effect;
        this.strength = strength;
    }

    public void actionPerformed(ActionEvent e) {
        effect.setStrength(strength);
        JoystickControl.ffjoystick.updateEffect(effect);
    }
}

class DirectionSelectionActionListener implements ActionListener {

    private ExtendedEffect effect;
    private Direction direction;

    DirectionSelectionActionListener(ExtendedEffect effect, Direction direction) {
        this.effect = effect;
        this.direction = direction;
    }

    public void actionPerformed(ActionEvent e) {
        effect.setDirection(direction);
        JoystickControl.ffjoystick.updateEffect(effect);

    }
}

class PlayEffectActionListener implements ActionListener {

    private Effect effect;

    PlayEffectActionListener(Effect effect) {
        this.effect = effect;
    }

    public void actionPerformed(ActionEvent e) {
        JoystickControl.ffjoystick.playEffect(effect, 1);

    }
}

class PlayEffectInfActionListener implements ActionListener {

    private Effect effect;

    PlayEffectInfActionListener(Effect effect) {
        this.effect = effect;
    }

    public void actionPerformed(ActionEvent e) {
        JoystickControl.ffjoystick.playEffect(effect, FFJoystick.INFINITE_TIMES);

    }
}